package anet

import (
	"gitee.com/AlexWoo/arpc"
)

var (
	rbPool = arpc.NewPool(func() any { return &RingBuffer{} })
)

func getRingBuffer(size uint32) *RingBuffer {
	rb := rbPool.Get().(*RingBuffer)

	if rb.bufferSize != size {
		rb.bufferSize = size
		rb.buffer = make([]*message, size)
	}

	rb.head = 0
	rb.tail = 0

	return rb
}

func putRingBuffer(s *session) {
	rb := s.sendbuf
	for !rb.empty() {
		msg := rb.PopHead()
		if msg.m.Code != 0 { // request delete in sendreq
			putMessage(msg)
		}
	}

	rbPool.Put(rb)
}

type RingBuffer struct {
	bufferSize uint32
	buffer     []*message
	head       uint32
	tail       uint32
}

func (rb *RingBuffer) empty() bool {
	return rb.head == rb.tail
}

func (rb *RingBuffer) full() bool {
	return (rb.tail+1)%rb.bufferSize == rb.head
}

func (rb *RingBuffer) Put(msg *message) *message {
	var head *message

	if rb.full() {
		head = rb.PopHead()
	}

	rb.buffer[rb.tail] = msg
	rb.tail = (rb.tail + 1) % rb.bufferSize

	return head
}

func (rb *RingBuffer) PopHead() *message {
	if rb.empty() {
		return nil
	}

	msg := rb.buffer[rb.head]
	rb.buffer[rb.head] = nil
	rb.head = (rb.head + 1) % rb.bufferSize

	return msg
}

func (rb *RingBuffer) Head() *message {
	if rb.empty() {
		return nil
	}

	msg := rb.buffer[rb.head]

	return msg
}

func (rb *RingBuffer) BufferSize() uint32 {
	if rb.head <= rb.tail {
		return rb.tail - rb.head
	}

	return rb.tail + rb.bufferSize - rb.head
}
